import { isNumber } from "lodash-unified";
import type { FormItemRule } from "@chulei-ui/element-plus";

declare type RuleGenerator = (field: string) => FormItemRule;

const _defaultTrigger = ["blur", "change"];

/**
 * 不能为空
 * @param field 待校验字段
 */
export const notEmpty: RuleGenerator = (field) => {
  return {
    trigger: _defaultTrigger,
    required: true,
    message: `${field}不能为空`,
  };
};

export const number = (field: string, required?: boolean, min?: number, max?: number, zero?: boolean): FormItemRule => {
  return {
    trigger: _defaultTrigger,
    required,
    validator(rule, value: number | undefined, callback) {
      if (value === undefined && required) {
        throw new Error(`${field}不能为空`);
      }
      if (zero && value === 0) {
        throw new Error(`${field}不能为0`);
      }
      if (isNumber(min) && isNumber(max) && (value! <= min || value! >= max)) {
        throw new Error(`${field}需要在${min}~${max}之间`);
      }
      if (isNumber(min) && value! <= min) {
        throw new Error(`${field}不能小于${min}`);
      }
      if (isNumber(max) && value! >= max) {
        throw new Error(`${field}不能大于${max}`);
      }
      callback();
    },
  };
};

export const length = (
  field: string,
  length: number,
  strict?: boolean,
  isNumber?: boolean,
  unsigned?: boolean,
  required?: boolean
): FormItemRule => {
  return {
    trigger: _defaultTrigger,
    required,
    validator(rule, value: string | undefined, callback) {
      const _length = value?.length ?? 0;
      if (!value && required) {
        return new Error(`${field}不能为空`);
      }
      if (!value && !required) {
        callback();
        return;
      }
      if (strict && _length !== length) {
        return new Error(`${field}长度必须为${length}当前${_length}`);
      }
      if (_length > length) {
        return new Error(`${field}长度必须小于${length}当前${_length}`);
      }
      if (isNumber && !value!.match(/^\d+$/)) {
        return new Error(`${field}必须是数字`);
      }
      if (isNumber && unsigned && !value!.match(/^(-)*\d+$/)) {
        return new Error(`${field}必须是一个正数`);
      }
      callback();
    },
  };
};

/**
 * 手机号校验
 * @returns {{validator: *, trigger: [string, string]}}
 */
export const mobile = (required = true): FormItemRule => {
  const regex = /^1[3456789]\d{9}$/;
  return {
    trigger: _defaultTrigger,
    required,
    validator(rule, value, callback) {
      if (!value && required) {
        return new Error("手机号不能为空");
      } else {
        if (value && !regex.test(value)) {
          return new Error("手机号格式不正确");
        }
        callback();
      }
    },
  };
};

export const simpleMobile: RuleGenerator = (field) => {
  const regex = /^[0-9]*$/;
  return {
    trigger: _defaultTrigger,
    validator(rule, value, callback) {
      if (value && !regex.test(value)) {
        return new Error(`${field}格式不正确`);
      }
      callback();
    },
  };
};

/**
 * 校验密码是否符合要求
 * @param field
 * @param comparePassword 比较的密码
 */
export const password = (field: string, comparePassword?: () => string | undefined): FormItemRule => {
  return {
    trigger: _defaultTrigger,
    required: true,
    validator(rule, value, callback) {
      if (value) {
        if (comparePassword && comparePassword() !== value) {
          callback(new Error(`密码和${field}不一致`));
          return;
        }
        if (value.length >= 6 && value.length <= 20) {
          //密码复杂度校验 数字 字母 特殊字符 任意两个条件满足
          const number = /\d/.test(value);
          const word = /[a-zA-Z]/.test(value);
          const spWord = /[.,?@;:%&*!]/.test(value);
          if ((number && word) || (number && spWord) || (word && spWord)) {
            callback();
            return;
          }
        }
        callback(new Error("6~20个字符,至少包含字母、数字、标点符号中的两种"));
      } else {
        callback(new Error("密码不能为空"));
      }
    },
  };
};

export const idCard = () => {
  const rule: FormItemRule = {
    validator: (rule, value, callback) => {
      if (value && !new IdCard(value).isValid()) {
        callback(new Error("身份证号码格式不正确"));
      } else {
        callback();
      }
    },
    trigger: ["blur", "change"],
  };
  return rule;
};

/**
 * 身份证
 */
export class IdCard {
  wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1];
  validCode = [1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2];
  size;
  id: (string | number)[];
  sum = 0;
  valCodePosition = -1;
  birthdayRange: Record<number, { year: number[]; month: number[]; day: number[] }> = {
    15: {
      year: [6, 8],
      month: [8, 10],
      day: [10, 12],
    },
    18: {
      year: [6, 10],
      month: [10, 12],
      day: [12, 14],
    },
  };

  constructor(input: string) {
    input = input.trim();
    this.size = input.length;
    this.id = input.split("");
  }

  isValid() {
    return (this.id.length === 15 || this.id.length === 18) && this._validBirthday() && this._validLast();
  }

  _validBirthday() {
    const realRange = this.birthdayRange[this.size];
    const year = Number.parseFloat(this.id.join("").slice(realRange.year[0], realRange.year[1]));
    const month = Number.parseFloat(this.id.join("").slice(realRange.month[0], realRange.month[1]));
    const day = Number.parseFloat(this.id.join("").slice(realRange.day[0], realRange.day[1]));
    const date = new Date(year, month - 1, day);
    if (this._getYear(date) !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
      return false;
    } else {
      return true;
    }
  }

  _validLast() {
    if (this.size === 18) {
      if ((this.id[17] as string).toLowerCase() === "x") {
        this.id[17] = 10; // 将最后位为x的验证码替换为10方便后续操作
      }
      for (let i = 0; i < 17; i++) {
        this.sum += this.wi[i] * (this.id[i] as number); // 加权求和
      }
      this.valCodePosition = this.sum % 11; // 得到验证码所位置
      return this.id[17] == this.validCode[this.valCodePosition];
    }
    return true;
  }

  _getYear(date: Date) {
    return this.size === 15 ? date.getFullYear() : date.getFullYear();
  }
}
